/*/////////////////////////////////////////////////////////*/
/*  Copyright Christopher Kormanyos 2017 - 2018.           */
/*  Distributed under the Boost Software License,          */
/*  Version 1.0. (See accompanying file LICENSE_1_0.txt    */
/*  or copy at http://www.boost.org/LICENSE_1_0.txt)       */
/*/////////////////////////////////////////////////////////*/

#include <math/checksums/crc/Crc32.h>
#include <mcal_memory_progmem.h>

void Crc32_Initialize(Crc32_Context_Type* Crc_Context)
{
  /* Set the initial value. */
  Crc_Context->Crc32_Value = UINT32_C(0xFFFFFFFF);
}

void Crc32_ProcessBytes(const uint8_t*      DataIn,
                        const size_t        DataLength,
                        Crc32_Context_Type* Crc_Context)
{
  size_t LoopCnt;

  /* Loop through the input data stream */
  for(LoopCnt = 0U; LoopCnt < DataLength; ++LoopCnt)
  {
    /* CRC-32/AUTOSAR Table based on 32-bit DWORDs. */

    static const uint32_t Crc32_Table[256U] MY_PROGMEM =
    {
      UINT32_C(0x00000000), UINT32_C(0x30850FF5), UINT32_C(0x610A1FEA), UINT32_C(0x518F101F), UINT32_C(0xC2143FD4), UINT32_C(0xF2913021), UINT32_C(0xA31E203E), UINT32_C(0x939B2FCB), 
      UINT32_C(0x159615F7), UINT32_C(0x25131A02), UINT32_C(0x749C0A1D), UINT32_C(0x441905E8), UINT32_C(0xD7822A23), UINT32_C(0xE70725D6), UINT32_C(0xB68835C9), UINT32_C(0x860D3A3C), 
      UINT32_C(0x2B2C2BEE), UINT32_C(0x1BA9241B), UINT32_C(0x4A263404), UINT32_C(0x7AA33BF1), UINT32_C(0xE938143A), UINT32_C(0xD9BD1BCF), UINT32_C(0x88320BD0), UINT32_C(0xB8B70425), 
      UINT32_C(0x3EBA3E19), UINT32_C(0x0E3F31EC), UINT32_C(0x5FB021F3), UINT32_C(0x6F352E06), UINT32_C(0xFCAE01CD), UINT32_C(0xCC2B0E38), UINT32_C(0x9DA41E27), UINT32_C(0xAD2111D2), 
      UINT32_C(0x565857DC), UINT32_C(0x66DD5829), UINT32_C(0x37524836), UINT32_C(0x07D747C3), UINT32_C(0x944C6808), UINT32_C(0xA4C967FD), UINT32_C(0xF54677E2), UINT32_C(0xC5C37817), 
      UINT32_C(0x43CE422B), UINT32_C(0x734B4DDE), UINT32_C(0x22C45DC1), UINT32_C(0x12415234), UINT32_C(0x81DA7DFF), UINT32_C(0xB15F720A), UINT32_C(0xE0D06215), UINT32_C(0xD0556DE0), 
      UINT32_C(0x7D747C32), UINT32_C(0x4DF173C7), UINT32_C(0x1C7E63D8), UINT32_C(0x2CFB6C2D), UINT32_C(0xBF6043E6), UINT32_C(0x8FE54C13), UINT32_C(0xDE6A5C0C), UINT32_C(0xEEEF53F9), 
      UINT32_C(0x68E269C5), UINT32_C(0x58676630), UINT32_C(0x09E8762F), UINT32_C(0x396D79DA), UINT32_C(0xAAF65611), UINT32_C(0x9A7359E4), UINT32_C(0xCBFC49FB), UINT32_C(0xFB79460E), 
      UINT32_C(0xACB0AFB8), UINT32_C(0x9C35A04D), UINT32_C(0xCDBAB052), UINT32_C(0xFD3FBFA7), UINT32_C(0x6EA4906C), UINT32_C(0x5E219F99), UINT32_C(0x0FAE8F86), UINT32_C(0x3F2B8073), 
      UINT32_C(0xB926BA4F), UINT32_C(0x89A3B5BA), UINT32_C(0xD82CA5A5), UINT32_C(0xE8A9AA50), UINT32_C(0x7B32859B), UINT32_C(0x4BB78A6E), UINT32_C(0x1A389A71), UINT32_C(0x2ABD9584), 
      UINT32_C(0x879C8456), UINT32_C(0xB7198BA3), UINT32_C(0xE6969BBC), UINT32_C(0xD6139449), UINT32_C(0x4588BB82), UINT32_C(0x750DB477), UINT32_C(0x2482A468), UINT32_C(0x1407AB9D), 
      UINT32_C(0x920A91A1), UINT32_C(0xA28F9E54), UINT32_C(0xF3008E4B), UINT32_C(0xC38581BE), UINT32_C(0x501EAE75), UINT32_C(0x609BA180), UINT32_C(0x3114B19F), UINT32_C(0x0191BE6A), 
      UINT32_C(0xFAE8F864), UINT32_C(0xCA6DF791), UINT32_C(0x9BE2E78E), UINT32_C(0xAB67E87B), UINT32_C(0x38FCC7B0), UINT32_C(0x0879C845), UINT32_C(0x59F6D85A), UINT32_C(0x6973D7AF), 
      UINT32_C(0xEF7EED93), UINT32_C(0xDFFBE266), UINT32_C(0x8E74F279), UINT32_C(0xBEF1FD8C), UINT32_C(0x2D6AD247), UINT32_C(0x1DEFDDB2), UINT32_C(0x4C60CDAD), UINT32_C(0x7CE5C258), 
      UINT32_C(0xD1C4D38A), UINT32_C(0xE141DC7F), UINT32_C(0xB0CECC60), UINT32_C(0x804BC395), UINT32_C(0x13D0EC5E), UINT32_C(0x2355E3AB), UINT32_C(0x72DAF3B4), UINT32_C(0x425FFC41), 
      UINT32_C(0xC452C67D), UINT32_C(0xF4D7C988), UINT32_C(0xA558D997), UINT32_C(0x95DDD662), UINT32_C(0x0646F9A9), UINT32_C(0x36C3F65C), UINT32_C(0x674CE643), UINT32_C(0x57C9E9B6), 
      UINT32_C(0xC8DF352F), UINT32_C(0xF85A3ADA), UINT32_C(0xA9D52AC5), UINT32_C(0x99502530), UINT32_C(0x0ACB0AFB), UINT32_C(0x3A4E050E), UINT32_C(0x6BC11511), UINT32_C(0x5B441AE4), 
      UINT32_C(0xDD4920D8), UINT32_C(0xEDCC2F2D), UINT32_C(0xBC433F32), UINT32_C(0x8CC630C7), UINT32_C(0x1F5D1F0C), UINT32_C(0x2FD810F9), UINT32_C(0x7E5700E6), UINT32_C(0x4ED20F13), 
      UINT32_C(0xE3F31EC1), UINT32_C(0xD3761134), UINT32_C(0x82F9012B), UINT32_C(0xB27C0EDE), UINT32_C(0x21E72115), UINT32_C(0x11622EE0), UINT32_C(0x40ED3EFF), UINT32_C(0x7068310A), 
      UINT32_C(0xF6650B36), UINT32_C(0xC6E004C3), UINT32_C(0x976F14DC), UINT32_C(0xA7EA1B29), UINT32_C(0x347134E2), UINT32_C(0x04F43B17), UINT32_C(0x557B2B08), UINT32_C(0x65FE24FD), 
      UINT32_C(0x9E8762F3), UINT32_C(0xAE026D06), UINT32_C(0xFF8D7D19), UINT32_C(0xCF0872EC), UINT32_C(0x5C935D27), UINT32_C(0x6C1652D2), UINT32_C(0x3D9942CD), UINT32_C(0x0D1C4D38), 
      UINT32_C(0x8B117704), UINT32_C(0xBB9478F1), UINT32_C(0xEA1B68EE), UINT32_C(0xDA9E671B), UINT32_C(0x490548D0), UINT32_C(0x79804725), UINT32_C(0x280F573A), UINT32_C(0x188A58CF), 
      UINT32_C(0xB5AB491D), UINT32_C(0x852E46E8), UINT32_C(0xD4A156F7), UINT32_C(0xE4245902), UINT32_C(0x77BF76C9), UINT32_C(0x473A793C), UINT32_C(0x16B56923), UINT32_C(0x263066D6), 
      UINT32_C(0xA03D5CEA), UINT32_C(0x90B8531F), UINT32_C(0xC1374300), UINT32_C(0xF1B24CF5), UINT32_C(0x6229633E), UINT32_C(0x52AC6CCB), UINT32_C(0x03237CD4), UINT32_C(0x33A67321), 
      UINT32_C(0x646F9A97), UINT32_C(0x54EA9562), UINT32_C(0x0565857D), UINT32_C(0x35E08A88), UINT32_C(0xA67BA543), UINT32_C(0x96FEAAB6), UINT32_C(0xC771BAA9), UINT32_C(0xF7F4B55C), 
      UINT32_C(0x71F98F60), UINT32_C(0x417C8095), UINT32_C(0x10F3908A), UINT32_C(0x20769F7F), UINT32_C(0xB3EDB0B4), UINT32_C(0x8368BF41), UINT32_C(0xD2E7AF5E), UINT32_C(0xE262A0AB), 
      UINT32_C(0x4F43B179), UINT32_C(0x7FC6BE8C), UINT32_C(0x2E49AE93), UINT32_C(0x1ECCA166), UINT32_C(0x8D578EAD), UINT32_C(0xBDD28158), UINT32_C(0xEC5D9147), UINT32_C(0xDCD89EB2), 
      UINT32_C(0x5AD5A48E), UINT32_C(0x6A50AB7B), UINT32_C(0x3BDFBB64), UINT32_C(0x0B5AB491), UINT32_C(0x98C19B5A), UINT32_C(0xA84494AF), UINT32_C(0xF9CB84B0), UINT32_C(0xC94E8B45), 
      UINT32_C(0x3237CD4B), UINT32_C(0x02B2C2BE), UINT32_C(0x533DD2A1), UINT32_C(0x63B8DD54), UINT32_C(0xF023F29F), UINT32_C(0xC0A6FD6A), UINT32_C(0x9129ED75), UINT32_C(0xA1ACE280), 
      UINT32_C(0x27A1D8BC), UINT32_C(0x1724D749), UINT32_C(0x46ABC756), UINT32_C(0x762EC8A3), UINT32_C(0xE5B5E768), UINT32_C(0xD530E89D), UINT32_C(0x84BFF882), UINT32_C(0xB43AF777), 
      UINT32_C(0x191BE6A5), UINT32_C(0x299EE950), UINT32_C(0x7811F94F), UINT32_C(0x4894F6BA), UINT32_C(0xDB0FD971), UINT32_C(0xEB8AD684), UINT32_C(0xBA05C69B), UINT32_C(0x8A80C96E), 
      UINT32_C(0x0C8DF352), UINT32_C(0x3C08FCA7), UINT32_C(0x6D87ECB8), UINT32_C(0x5D02E34D), UINT32_C(0xCE99CC86), UINT32_C(0xFE1CC373), UINT32_C(0xAF93D36C), UINT32_C(0x9F16DC99), 
    };

    /* Perform the CRC-32/AUTOSAR algorithm. */

    const uint_fast8_t DataIndex =
      (uint_fast8_t) (  ((uint_fast8_t) Crc_Context->Crc32_Value)
                      ^ ((uint_fast8_t) DataIn[LoopCnt]));

    const uint32_t TableValue =
      mcal_memory_progmem_read_dword((mcal_progmem_uintptr_t) &Crc32_Table[(uint8_t) DataIndex]);

    Crc_Context->Crc32_Value = (uint32_t) (Crc_Context->Crc32_Value >> 8U) ^ TableValue;
  }
}

void Crc32_Finalize(Crc32_Context_Type* Crc_Context)
{
  Crc_Context->Crc32_Value ^= UINT32_C(0xFFFFFFFF);
}
